package com.coco.seck.service.impl;

import com.coco.common.constant.Constant;
import com.coco.common.exception.CustomException;
import com.coco.common.exception.ErrorEnum;
import com.coco.common.result.CommonResponse;
import com.coco.common.util.IdWorker;
import com.coco.seck.mapper.DeployMapper;
import com.coco.seck.mapper.SeckillGoodsMapper;
import com.coco.seck.pojo.TbDeploy;
import com.coco.seck.pojo.TbSeckillGoods;
import com.coco.seck.service.SeckillService;
import com.coco.seck.vo.MqDeployVo;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author HanSama
 * @date 2021年07月16日 8:56
 */
@Service
@Slf4j
public class SeckillImpl implements SeckillService {

    @Autowired
    private IdWorker idWorker;

    private RedisTemplate redisTemplate;

    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        //Json 序列化配置
        Jackson2JsonRedisSerializer objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectJackson2JsonRedisSerializer.setObjectMapper(om);

        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(objectJackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(objectJackson2JsonRedisSerializer);
        this.redisTemplate = redisTemplate;
    }

    @Autowired
    private Redisson redisson;

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private DeployMapper deployMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private final int INIT_MAP_SIZE = 4;

    private final int STOCK_NUM = 1;


    /**
     * 秒杀前信息检查
     * @author HanSama
     * @date 2021/7/19 15:27
     * @param uid
     * @param gid
     * @return java.lang.String
     */
    @Override
    public CommonResponse doSeckKill(Integer uid, Integer gid) throws ParseException {

        //判单uid和gid是否为空
        if (uid==null || gid==null){
            return new CommonResponse(CommonResponse.BAD_REQUEST,"参数不能为空");
        }



        //设置分布式锁
        RLock lock = redisson.getLock(Constant.RedisKeyConstant.GOODS_LOCK_TEMPLATE+gid);
        try{
            //分布式锁 上锁
            lock.lock();
            //获取库存数量h
            int stock = (int) redisTemplate.opsForValue().get(Constant.RedisKeyConstant.GOODS_KEY_TEMPLATE+gid);
            //获取秒杀成功人名单和秒杀次数
            Map entries = redisTemplate.opsForHash().entries(Constant.RedisKeyConstant.GOODS_NUM_TEMPLATE+gid);
            //获取开始和结束时间
            Map timeMap = redisTemplate.opsForHash().entries("goods_time:" + gid);
            Time startTime = (Time) timeMap.get("startTime");
            Time endTime = (Time) timeMap.get("endTime");
            Date startDate = (Date) timeMap.get("startDate");
            Date endDate = (Date) timeMap.get("endDate");
            Date now = new Date();
            SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
            String formatDate = format.format(now);
            Date parse = format.parse(formatDate);

            if (startDate.getTime()<=now.getTime() && startTime.getTime()<=parse.getTime()){
                if (endDate.getTime()>=now.getTime() && endTime.getTime()>=parse.getTime()){
                    return checkNum(uid, gid, stock, entries);
                }else {
                    return new CommonResponse(CommonResponse.ERROR_CODE,"活动已结束");
                }
            }else {
                return new CommonResponse(CommonResponse.ERROR_CODE,"活动未开始");
            }
        }finally {
            //解锁
            lock.unlock();
        }



//                Random random = new Random();
//        int i = random.nextInt(2000);

//        //设置分布式锁
//        RLock lock = redisson.getLock(Constant.RedisKeyConstant.GOODS_LOCK_TEMPLATE+gid);
//        try{
//            //分布式锁 上锁
//            lock.lock();
//            //获取库存数量h
//            int stock = (int) redisTemplate.opsForValue().get(Constant.RedisKeyConstant.GOODS_KEY_TEMPLATE+gid);
//            //获取秒杀成功人名单和秒杀次数
//            Map entries = redisTemplate.opsForHash().entries(Constant.RedisKeyConstant.GOODS_NUM_TEMPLATE+gid);
//
//            if (entries!=null && entries.size()>0){
//                //获取当前用户秒杀的次数
//                Integer userNum = (Integer) entries.get(Constant.RedisKeyConstant.USER_TEMPLATE + i);
//                Integer numberOfActive = (Integer) entries.get(Constant.RedisKeyConstant.NUMBER_OF_ACTIVE);
//                if (userNum!=null && userNum<numberOfActive){
//                    //用户不是第一次购买 次数加一
//                    entries.put(Constant.RedisKeyConstant.USER_TEMPLATE+i,userNum+1);
//                    return SeckillGoods(i, gid, stock,entries);
//                }else if (userNum==null){
//                    //如果用户第一次购买
//                    entries.put(Constant.RedisKeyConstant.USER_TEMPLATE+i,1);
//                    redisTemplate.opsForHash().putAll(Constant.RedisKeyConstant.GOODS_NUM_TEMPLATE+gid,entries);
//                    return SeckillGoods(i, gid, stock, entries);
//                }else {
//                    return new CommonResponse(CommonResponse.ERROR_CODE,"已达到秒杀限制，不能重复秒杀");
//                }
//            }else {
//                //此商品是第一次被秒杀
//                TbSeckillGoods seckillGoods = seckillGoodsMapper.findOneById(gid.longValue());
//                //初始化goods限定数量 和 名单
//                int numberOfActive = seckillGoods.getNumberOfActive();
//                entries =  new HashMap<>();
//                entries.put(Constant.RedisKeyConstant.USER_TEMPLATE+i,1);
//                entries.put(Constant.RedisKeyConstant.NUMBER_OF_ACTIVE,numberOfActive);
//                return SeckillGoods(i, gid, stock, entries);
//            }
//        }finally {
//            //解锁
//            lock.unlock();
//        }
//


//        Random random = new Random();
//        int i = random.nextInt(2000);
//        RLock lock = redisson.getLock(Constant.RedisKeyConstant.GOODS_LOCK_TEMPLATE+gid);
//
//        try{
//            //分布式锁 上锁
//            lock.lock();
//            int stock = (int) redisTemplate.opsForValue().get(Constant.RedisKeyConstant.GOODS_KEY_TEMPLATE+gid);
//            if (redisTemplate.opsForSet().isMember(Constant.RedisKeyConstant.SOCK_USER_TEMPLATE+gid,i)){
//                System.out.println("已秒杀过，不能重复秒杀");
//            }else {
//                if (stock>0){
//                    //库存-1
//                    int realStock = stock-1;
//                    System.out.println("库存剩余"+realStock);
//                    redisTemplate.opsForValue().set(Constant.RedisKeyConstant.GOODS_KEY_TEMPLATE+gid,realStock);
//                    //将秒杀成功的用户加入set
//                    redisTemplate.opsForSet().add(Constant.RedisKeyConstant.SOCK_USER_TEMPLATE+gid,i);
//
//                    System.out.println("秒杀成功");
//                }else {
//                    System.out.println("秒杀失败，库存不足");
//                }
//            }
//        }finally {
//            //解锁
//            lock.unlock();
//        }
//return null;

    }


    private CommonResponse checkNum(Integer uid, Integer gid, int stock, Map entries) {
        if (entries !=null && entries.size()>0){
        //获取当前用户秒杀的次数
        Integer userNum = (Integer) entries.get(Constant.RedisKeyConstant.USER_TEMPLATE + uid);
        Integer numberOfActive = (Integer) entries.get(Constant.RedisKeyConstant.NUMBER_OF_ACTIVE);
        if (userNum!=null && userNum<numberOfActive){
            //用户不是第一次购买 次数加一
            entries.put(Constant.RedisKeyConstant.USER_TEMPLATE+ uid,userNum+1);
            return SeckillGoods(uid, gid, stock, entries);
        }else if (userNum==null){
            //如果用户第一次购买
            entries.put(Constant.RedisKeyConstant.USER_TEMPLATE+ uid,1);
            redisTemplate.opsForHash().putAll(Constant.RedisKeyConstant.GOODS_NUM_TEMPLATE+ gid, entries);
            return SeckillGoods(uid, gid, stock, entries);
        }else {
            return new CommonResponse(CommonResponse.ERROR_CODE,"已达到秒杀限制，不能重复秒杀");
        }
    }else {
        //此商品是第一次被秒杀
        TbSeckillGoods seckillGoods = seckillGoodsMapper.findOneById(gid.longValue());
        //初始化goods限定数量 和 名单
        int numberOfActive = seckillGoods.getNumberOfActive();
        entries =  new HashMap<>();
        entries.put(Constant.RedisKeyConstant.USER_TEMPLATE+ uid,1);
        entries.put(Constant.RedisKeyConstant.NUMBER_OF_ACTIVE,numberOfActive);
        return SeckillGoods(uid, gid, stock, entries);
        }
    }

    /**
     * 秒杀商品
     * @author HanSama
     * @date 2021/7/19 15:26
     * @param uid
     * @param gid
     * @param stock
     * @param entries
     * @return java.lang.String
     */
    private CommonResponse SeckillGoods(Integer uid, Integer gid, int stock, Map entries) {
        if (stock >0){
            //库存-1
            int realStock = stock -STOCK_NUM;
            log.info("库存剩余"+realStock);
            //更新库存
            redisTemplate.opsForValue().set(Constant.RedisKeyConstant.GOODS_KEY_TEMPLATE+ gid,realStock);
            //更新名单
            redisTemplate.opsForHash().putAll(Constant.RedisKeyConstant.GOODS_NUM_TEMPLATE+gid,entries);
            //将成功秒杀商品的用户id 和 商品id 存入map
            String orderNo = String.valueOf(idWorker.nextId());
            HashMap<String, Object> successMap = new HashMap<>(INIT_MAP_SIZE);
            successMap.put(Constant.OrderKeyConstant.USERKEY, uid.toString());
            successMap.put(Constant.OrderKeyConstant.GOODSKEY, gid.toString());
            successMap.put(Constant.OrderKeyConstant.ORDERKEY,orderNo);
            //发送给MQ生成订单
            rabbitTemplate.convertAndSend(Constant.RabbitMqKeyConstant.SEC_ORDER_EXCHANGE_KEY,"",successMap);
            log.info("秒杀成功");
           return new CommonResponse(CommonResponse.SUCCESS_CODE,"秒杀成功",orderNo);
        }else {
            log.info("秒杀失败，库存不足");
            return new CommonResponse(CommonResponse.ERROR_CODE,"秒杀失败，库存不足");
        }
    }

    @Override
    public String addSeckGoods() {
        TbDeploy deploy = deployMapper.selectById(1L);
        TbSeckillGoods seckillGoods = seckillGoodsMapper.findOneById(1L);

        rabbitTemplate.convertAndSend(Constant.RabbitMqKeyConstant.ADD_REDIS_KILL_GOODS_KEY,"",new MqDeployVo(deploy,seckillGoods));

//        String goodsKey = "seck_goods:"+1;
//        redisTemplate.opsForValue().set(goodsKey,300);
        return "添加成功";
    }

}
